package com.log4jviewer.server;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;

import org.apache.log4j.spi.LoggingEvent;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.log4jviewer.domain.LogEvent;
import com.log4jviewer.domain.SocketLogEvent;

/**
 * Class defines client connection in a separate thread. Server gets from client input stream log message and put it to
 * log list.
 * 
 * @author <a href="mailto:rd.ryly@gmail.com">Ruslan Diachenko</a>
 */
public class ClientConnection extends Thread {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private Server server;

    private Socket socket;

    public ClientConnection(final Server server, final Socket socket) {
        this.server = server;
        this.socket = socket;
    }

    @Override
    public void run() {
        ObjectInputStream inputStream = null;
        logger.debug("Client connection was started.");

        try {
            inputStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));

            while (!socket.isClosed()) {
                LoggingEvent log = (LoggingEvent) inputStream.readObject();
                sendLogToList(log);
                logger.debug("Server activity: {}", !socket.isClosed());
            }

        } catch (IOException e) {
            String errorMessage = "Wrong client input stream!";
            server.sendError(errorMessage);
            logger.error(errorMessage, e);

        } catch (ClassNotFoundException e) {
            String errorMessage = "Couldn't recognized LoggingEvent object from input stream!";
            server.sendError(errorMessage);
            logger.error(errorMessage, e);

        } finally {
            try {
                inputStream.close();

                if (!socket.isClosed()) {
                    socket.shutdownOutput();
                    socket.shutdownInput();
                    socket.close();
                    logger.info("Client connection was successfuly closed!");
                }
            } catch (IOException e) {
                String errorMessage = "Socket couldn't be closed successfuly!";
                server.sendError(errorMessage);
                logger.error(errorMessage, e);
            }
        }
    }

    public synchronized void sendLogToList(final LoggingEvent log) {
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                LogEvent logEvent = new SocketLogEvent(log);
                server.notifyListeners(logEvent);
            }
        });
    }
}
